package com.xu.sso.client.filter;

import com.alibaba.fastjson.JSONObject;
import com.xu.sso.client.config.SSOConfig;
import com.xu.sso.client.model.AppPathRole;
import com.xu.sso.client.model.UserLoginInfo;
import com.xu.sso.client.utils.ClientRedisUtil;
import com.xu.sso.client.utils.CookiesUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

@Component
@Order(1)
public class LoginFilter extends GenericFilterBean {

    @Value("${com.xu.sso.service.path}")
    private String servicePath;
    @Value("${com.xu.sso.logout.path}")
    private String logoutPath;
    @Value("${com.xu.sso.app_id}")
    private String appId;
    @Value("${com.xu.sso.interval:10000}")
    private long interval;
    private long expiration;
    @Autowired
    private ClientRedisUtil redisUtil;

    private PathMatcher pathMatcher;

    static List<AppPathRole> pathRoles;
    static Set<String> staticUrl;
    static Set<String> authUrl;

    public static final ThreadLocal<UserLoginInfo> threadLocal = new ThreadLocal<>();

    @Override
    public void initFilterBean() throws ServletException {
        String value = redisUtil.getStringValue(SSOConfig.REDIS_SET + appId);
        if (null != value && value.length() > 0) {
            pathRoles = JSONObject.parseArray(value, AppPathRole.class);
        }
        authUrl = new HashSet<>();
        staticUrl = new HashSet<>();
        if (null != pathRoles) {
            for (AppPathRole appPathRole : pathRoles) {
                if (appPathRole.isLogin()) {
                    authUrl.add(appPathRole.getPath());
                } else {
                    staticUrl.add(appPathRole.getPath());
                }
            }
        } else {
            pathRoles = new ArrayList<>();
        }
        expiration = interval + System.currentTimeMillis();
        pathMatcher = new AntPathMatcher();
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String servletPath = request.getServletPath();
        String requestType = request.getHeader("X-Requested-With");
        String token = CookiesUtil.getValue(request, SSOConfig.TOKEN);
        if (null == token || token.trim().length() == 0) {
            token = request.getHeader(SSOConfig.TOKEN);
        }

        // 用户注销
        if (null != logoutPath && logoutPath.trim().length() > 0 && servletPath.endsWith(logoutPath)) {

            // 删除cookie
            CookiesUtil.remove(request, response, SSOConfig.TOKEN);

            String logoutPageUrl = servicePath + SSOConfig.LOGOUT + "?" + SSOConfig.TOKEN + "=" + token + "&" + SSOConfig.APP_ID + "=" + appId;

            if (SSOConfig.AJAX_REQ.equalsIgnoreCase(requestType)) {
//                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, logoutPageUrl);
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setContentType("text/html;charset=utf-8;");
                response.getWriter().println(logoutPageUrl);
            } else {
                response.sendRedirect(logoutPageUrl);
            }
            return;
        }

        if (expiration <= System.currentTimeMillis()) {
            String value = redisUtil.getStringValue(SSOConfig.REDIS_SET + appId);
            if (null != value && value.length() > 0) {
                pathRoles = JSONObject.parseArray(value, AppPathRole.class);
            }
            if (null != pathRoles) {
                for (AppPathRole appPathRole : pathRoles) {
                    if (appPathRole.isLogin()) {
                        authUrl.add(appPathRole.getPath());
                    } else {
                        staticUrl.add(appPathRole.getPath());
                    }
                }
            }
            expiration = interval + System.currentTimeMillis();
        }

        long authCount = authUrl.stream().filter(u -> pathMatcher.match(u, servletPath)).count();
        long staticCount = 0;
        if (authCount == 0) {
            staticCount = staticUrl.stream().filter(u -> pathMatcher.match(u, servletPath)).count();
        }

        UserLoginInfo userLoginInfo = null;
        if (null != token && token.trim().length() > 0) {
            userLoginInfo = redisUtil.getObjectValue(SSOConfig.REDIS_SET + token, UserLoginInfo.class);
        }
        if (null == userLoginInfo) {
            // 删除老的cookie
            CookiesUtil.remove(request, response, SSOConfig.TOKEN);
            token = request.getParameter(SSOConfig.TOKEN);
            if (null == token || token.trim().length() == 0) {
                token = request.getHeader(SSOConfig.TOKEN);
            }
            if (null != token && token.trim().length() > 0) {
                userLoginInfo = redisUtil.getObjectValue(SSOConfig.REDIS_SET + token, UserLoginInfo.class);
                if (null != userLoginInfo) {
                    // 添加新cookie
                    CookiesUtil.set(response, SSOConfig.TOKEN, token);
                }
            }
        }

        if (authCount > 0 || staticCount == 0) {

            if (null == userLoginInfo || !userLoginInfo.getAppRoles().containsKey(appId)) {
                String loginPageUrl = servicePath + SSOConfig.LOGIN + "?" + SSOConfig.APP_ID + "=" + appId;
                if (SSOConfig.AJAX_REQ.equalsIgnoreCase(requestType)) {
//                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, loginPageUrl);
                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                    response.setContentType("text/html;charset=utf-8;");
                    response.getWriter().println(loginPageUrl);
                } else {
                    response.sendRedirect(loginPageUrl);
                }
                return;
            }
            // 判断IP是否一致
//            String ip = IpAddrUtil.getIpAddress(request);
//            if (!ip.equals(userLoginInfo.getIp())) {
//                String loginPageUrl = servicePath + SSOConfig.LOGIN + "?" + SSOConfig.APP_ID + "=" + appId;
//                if (SSOConfig.AJAX_REQ.equalsIgnoreCase(requestType)) {
//                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, loginPageUrl);
//                } else {
//                    response.sendRedirect(loginPageUrl);
//                }
//                return;
//            }

            // 刷新缓存
            redisUtil.expire(SSOConfig.REDIS_SET + token, SSOConfig.EXPIRATION);

        }

        if (null != userLoginInfo) {
            request.setAttribute(SSOConfig.SSO_USER, userLoginInfo);
            threadLocal.set(userLoginInfo);
        }

        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}
